package service

import (
	"admin-nexus-backend/internal/dto"
	"admin-nexus-backend/pkg/logger"
	"context"
	"encoding/json"
	"fmt"
	"time"

	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
)

const (
	// 缓存键前缀
	cacheKeyUserPermissions    = "permission:user:%d:permissions" // 用户权限码列表
	cacheKeyUserMenus          = "permission:user:%d:menus"       // 用户菜单列表
	cacheKeyUserDataPermission = "permission:user:%d:data"        // 用户数据权限
	cacheKeyRolePermissions    = "permission:role:%d:permissions" // 角色权限

	// 缓存过期时间
	cacheExpireTime = 30 * time.Minute // 30分钟
)

// PermissionCacheService 权限缓存服务
type PermissionCacheService struct {
	rdb *redis.Client
	ctx context.Context
}

// NewPermissionCacheService 创建权限缓存服务
func NewPermissionCacheService(rdb *redis.Client) *PermissionCacheService {
	return &PermissionCacheService{
		rdb: rdb,
		ctx: context.Background(),
	}
}

// ==================== 用户权限码缓存 ====================

// GetUserPermissions 获取用户权限码（从缓存）
func (s *PermissionCacheService) GetUserPermissions(userID uint) ([]string, error) {
	if s.rdb == nil {
		return nil, fmt.Errorf("Redis未初始化")
	}

	key := fmt.Sprintf(cacheKeyUserPermissions, userID)
	val, err := s.rdb.Get(s.ctx, key).Result()

	if err == redis.Nil {
		// 缓存未命中
		return nil, nil
	}

	if err != nil {
		logger.Error("获取用户权限缓存失败", zap.Error(err), zap.Uint("userID", userID))
		return nil, err
	}

	var permissions []string
	if err := json.Unmarshal([]byte(val), &permissions); err != nil {
		logger.Error("解析用户权限缓存失败", zap.Error(err), zap.Uint("userID", userID))
		return nil, err
	}

	logger.Debug("从缓存获取用户权限成功", zap.Uint("userID", userID), zap.Int("count", len(permissions)))
	return permissions, nil
}

// SetUserPermissions 设置用户权限码缓存
func (s *PermissionCacheService) SetUserPermissions(userID uint, permissions []string) error {
	if s.rdb == nil {
		return fmt.Errorf("Redis未初始化")
	}

	key := fmt.Sprintf(cacheKeyUserPermissions, userID)
	data, err := json.Marshal(permissions)
	if err != nil {
		logger.Error("序列化用户权限失败", zap.Error(err), zap.Uint("userID", userID))
		return err
	}

	if err := s.rdb.Set(s.ctx, key, data, cacheExpireTime).Err(); err != nil {
		logger.Error("设置用户权限缓存失败", zap.Error(err), zap.Uint("userID", userID))
		return err
	}

	logger.Debug("设置用户权限缓存成功", zap.Uint("userID", userID), zap.Int("count", len(permissions)))
	return nil
}

// ==================== 用户菜单缓存 ====================

// GetUserMenus 获取用户菜单（从缓存）
func (s *PermissionCacheService) GetUserMenus(userID uint) ([]*dto.MenuData, error) {
	if s.rdb == nil {
		return nil, fmt.Errorf("Redis未初始化")
	}

	key := fmt.Sprintf(cacheKeyUserMenus, userID)
	val, err := s.rdb.Get(s.ctx, key).Result()

	if err == redis.Nil {
		// 缓存未命中
		return nil, nil
	}

	if err != nil {
		logger.Error("获取用户菜单缓存失败", zap.Error(err), zap.Uint("userID", userID))
		return nil, err
	}

	var menus []*dto.MenuData
	if err := json.Unmarshal([]byte(val), &menus); err != nil {
		logger.Error("解析用户菜单缓存失败", zap.Error(err), zap.Uint("userID", userID))
		return nil, err
	}

	logger.Debug("从缓存获取用户菜单成功", zap.Uint("userID", userID), zap.Int("count", len(menus)))
	return menus, nil
}

// SetUserMenus 设置用户菜单缓存
func (s *PermissionCacheService) SetUserMenus(userID uint, menus []*dto.MenuData) error {
	if s.rdb == nil {
		return fmt.Errorf("Redis未初始化")
	}

	key := fmt.Sprintf(cacheKeyUserMenus, userID)
	data, err := json.Marshal(menus)
	if err != nil {
		logger.Error("序列化用户菜单失败", zap.Error(err), zap.Uint("userID", userID))
		return err
	}

	if err := s.rdb.Set(s.ctx, key, data, cacheExpireTime).Err(); err != nil {
		logger.Error("设置用户菜单缓存失败", zap.Error(err), zap.Uint("userID", userID))
		return err
	}

	logger.Debug("设置用户菜单缓存成功", zap.Uint("userID", userID), zap.Int("count", len(menus)))
	return nil
}

// ==================== 用户数据权限缓存 ====================

// GetUserDataPermission 获取用户数据权限（从缓存）
func (s *PermissionCacheService) GetUserDataPermission(userID uint) (*UserDataPermission, error) {
	if s.rdb == nil {
		return nil, fmt.Errorf("Redis未初始化")
	}

	key := fmt.Sprintf(cacheKeyUserDataPermission, userID)
	val, err := s.rdb.Get(s.ctx, key).Result()

	if err == redis.Nil {
		// 缓存未命中
		return nil, nil
	}

	if err != nil {
		logger.Error("获取用户数据权限缓存失败", zap.Error(err), zap.Uint("userID", userID))
		return nil, err
	}

	var dataPermission UserDataPermission
	if err := json.Unmarshal([]byte(val), &dataPermission); err != nil {
		logger.Error("解析用户数据权限缓存失败", zap.Error(err), zap.Uint("userID", userID))
		return nil, err
	}

	logger.Debug("从缓存获取用户数据权限成功", zap.Uint("userID", userID))
	return &dataPermission, nil
}

// SetUserDataPermission 设置用户数据权限缓存
func (s *PermissionCacheService) SetUserDataPermission(userID uint, dataPermission *UserDataPermission) error {
	if s.rdb == nil {
		return fmt.Errorf("Redis未初始化")
	}

	key := fmt.Sprintf(cacheKeyUserDataPermission, userID)
	data, err := json.Marshal(dataPermission)
	if err != nil {
		logger.Error("序列化用户数据权限失败", zap.Error(err), zap.Uint("userID", userID))
		return err
	}

	if err := s.rdb.Set(s.ctx, key, data, cacheExpireTime).Err(); err != nil {
		logger.Error("设置用户数据权限缓存失败", zap.Error(err), zap.Uint("userID", userID))
		return err
	}

	logger.Debug("设置用户数据权限缓存成功", zap.Uint("userID", userID))
	return nil
}

// ==================== 清除缓存 ====================

// ClearUserPermissionCache 清除用户的所有权限缓存
func (s *PermissionCacheService) ClearUserPermissionCache(userID uint) error {
	if s.rdb == nil {
		return fmt.Errorf("Redis未初始化")
	}

	keys := []string{
		fmt.Sprintf(cacheKeyUserPermissions, userID),
		fmt.Sprintf(cacheKeyUserMenus, userID),
		fmt.Sprintf(cacheKeyUserDataPermission, userID),
	}

	if err := s.rdb.Del(s.ctx, keys...).Err(); err != nil {
		logger.Error("清除用户权限缓存失败", zap.Error(err), zap.Uint("userID", userID))
		return err
	}

	logger.Info("清除用户权限缓存成功", zap.Uint("userID", userID))
	return nil
}

// ClearRolePermissionCache 清除角色权限缓存（当角色权限变更时）
func (s *PermissionCacheService) ClearRolePermissionCache(roleID uint) error {
	if s.rdb == nil {
		return fmt.Errorf("Redis未初始化")
	}

	key := fmt.Sprintf(cacheKeyRolePermissions, roleID)
	if err := s.rdb.Del(s.ctx, key).Err(); err != nil {
		logger.Error("清除角色权限缓存失败", zap.Error(err), zap.Uint("roleID", roleID))
		return err
	}

	logger.Info("清除角色权限缓存成功", zap.Uint("roleID", roleID))
	return nil
}

// ClearAllPermissionCache 清除所有权限缓存（谨慎使用）
func (s *PermissionCacheService) ClearAllPermissionCache() error {
	if s.rdb == nil {
		return fmt.Errorf("Redis未初始化")
	}

	// 使用 SCAN 命令查找所有权限相关的键
	iter := s.rdb.Scan(s.ctx, 0, "permission:*", 0).Iterator()
	var keys []string
	for iter.Next(s.ctx) {
		keys = append(keys, iter.Val())
	}

	if err := iter.Err(); err != nil {
		logger.Error("扫描权限缓存键失败", zap.Error(err))
		return err
	}

	if len(keys) > 0 {
		if err := s.rdb.Del(s.ctx, keys...).Err(); err != nil {
			logger.Error("批量删除权限缓存失败", zap.Error(err), zap.Int("count", len(keys)))
			return err
		}
	}

	logger.Info("清除所有权限缓存成功", zap.Int("count", len(keys)))
	return nil
}

// ==================== 批量清除缓存 ====================

// ClearUsersCaches 批量清除多个用户的权限缓存
func (s *PermissionCacheService) ClearUsersCaches(userIDs []uint) error {
	if s.rdb == nil {
		return fmt.Errorf("Redis未初始化")
	}

	var keys []string
	for _, userID := range userIDs {
		keys = append(keys,
			fmt.Sprintf(cacheKeyUserPermissions, userID),
			fmt.Sprintf(cacheKeyUserMenus, userID),
			fmt.Sprintf(cacheKeyUserDataPermission, userID),
		)
	}

	if len(keys) > 0 {
		if err := s.rdb.Del(s.ctx, keys...).Err(); err != nil {
			logger.Error("批量清除用户权限缓存失败", zap.Error(err), zap.Int("userCount", len(userIDs)))
			return err
		}
	}

	logger.Info("批量清除用户权限缓存成功", zap.Int("userCount", len(userIDs)))
	return nil
}

// ==================== 缓存统计 ====================

// GetCacheStats 获取权限缓存统计信息
func (s *PermissionCacheService) GetCacheStats() (map[string]interface{}, error) {
	if s.rdb == nil {
		return nil, fmt.Errorf("Redis未初始化")
	}

	stats := make(map[string]interface{})

	// 统计各类缓存数量
	patterns := map[string]string{
		"user_permissions": "permission:user:*:permissions",
		"user_menus":       "permission:user:*:menus",
		"user_data":        "permission:user:*:data",
		"role_permissions": "permission:role:*:permissions",
	}

	for name, pattern := range patterns {
		iter := s.rdb.Scan(s.ctx, 0, pattern, 0).Iterator()
		count := 0
		for iter.Next(s.ctx) {
			count++
		}
		if err := iter.Err(); err != nil {
			logger.Error("统计缓存失败", zap.String("pattern", pattern), zap.Error(err))
			continue
		}
		stats[name] = count
	}

	return stats, nil
}

// IsRedisAvailable 检查Redis是否可用
func (s *PermissionCacheService) IsRedisAvailable() bool {
	if s.rdb == nil {
		return false
	}
	return s.rdb.Ping(s.ctx).Err() == nil
}
